using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Runtime.InteropServices;

namespace SkyBase
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        World theWorld;
        OverlayManager ovManager;//Manages UIs
        public Rectangle viewportSize { get; set; }
        public Rectangle inventoryBox;
        Rectangle hoverBox;
        Rectangle pointerLoc;
        Vector2 pointerRaw = new Vector2(0, 0);
        public MouseState mouseState { get; set; }
        public MouseState previousMouseState { get; set; }

        public KeyboardState keyboardState;
        public KeyboardState previousKeyboardState;

        public SpriteFont arial { get; set; }
        public SpriteFont arialBold { get; set; }

        private Vector2 cameraPos;
        private Matrix cameraTransform;

        //Texture2D redPixel;
        //Texture2D pointer;
        int timeCheck;

        bool drawInventory = false;
        bool drawJump = false;
        bool newCycle = false;
        //bool canJump = true;
        public bool jumping = false; //if the player is jumping, DO NOT allow player control
        //double length = 0;
        public double prevLength { get; set; }
        int jumpCount = 0;
        int currentJumpCount = 0;
        //Vector2 finalJumpPos;

        [DllImport("user32.dll")]
        static extern void ClipCursor(ref Rectangle rect);


        public Game1()
        {
            Debugger.enabled = true;
            Content.RootDirectory = "Content";
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 768;
            IsMouseVisible = true;
            Storage.content = this.Content;   
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.

        /// </summary>
        protected override void Initialize()
        {
            Debugger.debug("Initializing");
            // TODO: Add your initialization logic here
            Window.AllowUserResizing = false;
            
            viewportSize = new Rectangle(0, 0, this.Window.ClientBounds.Width, this.Window.ClientBounds.Height);
            inventoryBox = new Rectangle(32, 32, 230, 225);
            hoverBox = new Rectangle(275, 225, 1, 1);
            pointerLoc = new Rectangle(40, 45, 10, 10);
            //floor = new Rectangle(0, 0, 1280, 768);

            cameraPos = new Vector2(viewportSize.X / 2, viewportSize.Y / 2);
            cameraTransform = Matrix.CreateTranslation(cameraPos.X, cameraPos.Y, 0.0f) * Matrix.CreateTranslation(viewportSize.X * 0.5f, viewportSize.Y * 0.5f, 0);


            base.Initialize();

            ovManager = new OverlayManager();
            ovManager.addOverlay(new MainMenu(this));
            //ovManager.addOverlay(new GameOver(this));
            ovManager.addOverlay(new HealthOverlay(theWorld.GetObject("player")));
            
            Debugger.debug("Initialization complete");

        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            Debugger.debug("Loading game content");
            Storage.loadContent();
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            theWorld = new World(this);
            arial = Content.Load<SpriteFont>("Arial");
            arialBold = Content.Load<SpriteFont>("ArialBold");
            theWorld.Initialize();
            cameraPos = -theWorld.objects["player"].Location;
            cameraTransform = Matrix.CreateTranslation(cameraPos.X, cameraPos.Y, 0.0f) * Matrix.CreateTranslation(viewportSize.Width * 0.5f, viewportSize.Height * 0.5f, 0);
            timeCheck = 0;
            Debugger.debug("Game contents loaded");
            // TODO: use this.Content to load your game content here
        }


        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {

            ovManager.Update(gameTime, -cameraPos - new Vector2(viewportSize.Width / 2, viewportSize.Height / 2));
            if (!ovManager.hold)
            {
                Line l = (Line)theWorld.objects["jumpLine"];
                Player p = (Player)theWorld.objects["player"];
                newCycle = true;
                previousKeyboardState = keyboardState;
                keyboardState = Keyboard.GetState();

                if (p.Health <= 0)
                    ovManager.addOverlay(new GameOver(this));

                if (IsActive)
                {
                    Rectangle rect = Window.ClientBounds;
                    rect.Width += rect.X;
                    rect.Height += rect.Y;

                    ClipCursor(ref rect);
                }

                // Allows the game to pause
                if (keyboardState.IsKeyDown(Keys.Escape))
                    ovManager.reAttachOverlay("MainMenu");

                #region Moving Input
                if (!jumping)
                {
                    if (keyboardState.IsKeyDown(Keys.W) && keyboardState.IsKeyUp(Keys.S))
                    {
                        if (theWorld.objects["player"].VY <= 0)
                        {
                            theWorld.objects["player"].direction = direction.TOP;
                            theWorld.objects["player"].VY -= 0.5f;
                        }
                        else theWorld.objects["player"].VY = -0.5f;
                    }
                    else if (keyboardState.IsKeyDown(Keys.S) && keyboardState.IsKeyUp(Keys.W))
                    {
                        if (theWorld.objects["player"].VY >= 0)
                        {
                            theWorld.objects["player"].direction = direction.BOTTOM;
                            theWorld.objects["player"].VY += 0.5f;
                        }
                        else theWorld.objects["player"].VY = 0.5f;
                    }
                    else if (theWorld.objects["player"].VY > 0)
                    {
                        theWorld.objects["player"].VY = theWorld.objects["player"].VY / 2;
                        if (theWorld.objects["player"].VY < 1f) theWorld.objects["player"].VY = 0;
                    }
                    else if (theWorld.objects["player"].VY < 0.5)
                    {
                        theWorld.objects["player"].VY = theWorld.objects["player"].VY / 2;
                        if (theWorld.objects["player"].VY > -0.5f) theWorld.objects["player"].VY = 0;
                    }

                    if (keyboardState.IsKeyDown(Keys.A) && keyboardState.IsKeyUp(Keys.D))
                    {
                        if (theWorld.objects["player"].VX <= 0)
                        {
                            theWorld.objects["player"].direction = direction.LEFT;
                            theWorld.objects["player"].VX -= 0.5f;
                        }
                        else theWorld.objects["player"].VX = -0.5f;
                    }
                    else if (keyboardState.IsKeyDown(Keys.D) && keyboardState.IsKeyUp(Keys.A))
                    {
                        if (theWorld.objects["player"].VX >= 0)
                        {
                            theWorld.objects["player"].direction = direction.RIGHT;
                            theWorld.objects["player"].VX += 0.5f;
                        }
                        else theWorld.objects["player"].VX = 0.5f;
                    }
                    else if (theWorld.objects["player"].VX > 0)
                    {
                        theWorld.objects["player"].VX = theWorld.objects["player"].VX / 2;
                        if (theWorld.objects["player"].VX < 0.5f) theWorld.objects["player"].VX = 0;
                    }
                    else if (theWorld.objects["player"].VX < 0)
                    {
                        theWorld.objects["player"].VX = theWorld.objects["player"].VX / 2;
                        if (theWorld.objects["player"].VX > -0.5f) theWorld.objects["player"].VX = 0;
                    }

                    if (keyboardState.IsKeyDown(Keys.W) && keyboardState.IsKeyDown(Keys.D))
                        theWorld.objects["player"].direction = direction.TOPRIGHT;
                    if (keyboardState.IsKeyDown(Keys.W) && keyboardState.IsKeyDown(Keys.A))
                        theWorld.objects["player"].direction = direction.TOPLEFT;
                    if (keyboardState.IsKeyDown(Keys.S) && keyboardState.IsKeyDown(Keys.A))
                        theWorld.objects["player"].direction = direction.BOTTOMLEFT;
                    if (keyboardState.IsKeyDown(Keys.S) && keyboardState.IsKeyDown(Keys.D))
                        theWorld.objects["player"].direction = direction.BOTTOMRIGHT;
                }
                #endregion


                #region Inventory commands
                if (drawInventory && timeCheck > 7)
                {
                    newCycle = false;
                    inventoryBox.X = (int)(theWorld.GetObject("player").Location.X) - (viewportSize.Width / 2) + 32;
                    inventoryBox.Y = (int)(theWorld.GetObject("player").Location.Y) - (viewportSize.Height / 2) + 32;
                    pointerLoc.X = (int)(theWorld.GetObject("player").Location.X) - (viewportSize.Width / 2) + 42;
                    pointerLoc.Y = (int)(theWorld.GetObject("player").Location.Y) - (viewportSize.Height / 2) + 45 + (int)(23 * pointerRaw.Y);
                    Player tempPlayer = (Player)(theWorld.objects["player"]);
                    if (keyboardState.IsKeyDown(Keys.Down) && timeCheck > 7 && tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                    {
                        timeCheck = 0;
                        if (pointerRaw.Y < 8)
                        {
                            if (tempPlayer.Inventory[(int)pointerRaw.Y + 1] != null && pointerRaw.Y < tempPlayer.Inventory.Length)
                            {
                                pointerLoc.Y += 23;
                                pointerRaw.Y++;
                            }
                        }
                    }
                    if (keyboardState.IsKeyDown(Keys.Up) && timeCheck > 7 && tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                    {
                        timeCheck = 0;
                        if (pointerRaw.Y > 0 && tempPlayer.Inventory[(int)pointerRaw.Y - 1] != null)
                        {
                            pointerLoc.Y -= 23;
                            pointerRaw.Y--;
                        }
                    }

                    if (keyboardState.IsKeyDown(Keys.Enter) && timeCheck > 7)
                    {
                        timeCheck = 0;
                        if (tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                            tempPlayer.swapWeapon((Weapon)tempPlayer.Inventory[(int)pointerRaw.Y]);
                        //tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor = Color.Aqua;
                        else
                            tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor = Color.White;
                    }

                    if (previousKeyboardState.IsKeyDown(Keys.Space) && keyboardState.IsKeyUp(Keys.Space))
                    {
                        drawInventory = false;
                        pointerRaw.Y = 0;
                        //Debugger.writeLine("Space hit!");
                    }
                }
                if (!drawInventory && previousKeyboardState.IsKeyDown(Keys.Space) && keyboardState.IsKeyUp(Keys.Space) && timeCheck > 7 && newCycle)
                {
                    drawInventory = true;
                    //Debugger.writeLine("Space hit!");
                }

                /*if (keyboardState.IsKeyDown(Keys.Space))
                {
                    inventoryBox.X = (int)(theWorld.GetObject("player").Location.X) - (viewportSize.Width / 2) + 32;
                    inventoryBox.Y = (int)(theWorld.GetObject("player").Location.Y) - (viewportSize.Height / 2) + 32;
                    pointerLoc.X = (int)(theWorld.GetObject("player").Location.X) - (viewportSize.Width / 2) + 42;
                    pointerLoc.Y = (int)(theWorld.GetObject("player").Location.Y) - (viewportSize.Height / 2) + 45 + (int)(23 * pointerRaw.Y);
                    Player tempPlayer = (Player)(theWorld.objects["player"]);
                    drawInventory = true;
                    if (keyboardState.IsKeyDown(Keys.Down) && timeCheck > 7 && tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                    {
                        timeCheck = 0;
                        if (pointerRaw.Y < 8)
                        {
                            if (tempPlayer.Inventory[(int)pointerRaw.Y + 1] != null && pointerRaw.Y < tempPlayer.Inventory.Length)
                            {
                                pointerLoc.Y += 23;
                                pointerRaw.Y++;
                            }
                        }
                    }
                    if (keyboardState.IsKeyDown(Keys.Up) && timeCheck > 7 && tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                    {
                        timeCheck = 0;
                        if (pointerRaw.Y > 0 && tempPlayer.Inventory[(int)pointerRaw.Y-1] != null)
                        {
                            pointerLoc.Y -= 23;
                            pointerRaw.Y--;
                        }
                    }

                    if (keyboardState.IsKeyDown(Keys.Enter) && timeCheck > 7)
                    {
                        timeCheck = 0;
                        if (tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor != Color.Aqua)
                            tempPlayer.swapWeapon((Weapon)tempPlayer.Inventory[(int)pointerRaw.Y]);
                        //tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor = Color.Aqua;
                        else
                            tempPlayer.Inventory[(int)pointerRaw.Y].InventoryColor = Color.White;
                    }
                }
                if (keyboardState.IsKeyUp(Keys.Space))
                {
                    drawInventory = false;
                    pointerRaw.Y = 0;
                }*/
                #endregion

                #region Mouse commands

                previousMouseState = mouseState;
                mouseState = Mouse.GetState();
                timeCheck++;

                if (mouseState.LeftButton.ToString().Equals("Pressed") && previousMouseState.LeftButton.ToString().Equals("Released"))
                {
                    if (!jumping)
                    {
                        if (keyboardState.IsKeyDown(Keys.LeftControl) || keyboardState.IsKeyDown(Keys.RightControl))//player is jumping
                        {
                            if (l.lineColor != Color.Red)
                            {
                                jumping = true;
                                drawJump = false;
                                jumpCount = theWorld.player.Jump();
                            }
                        }
                        else
                            theWorld.playerFireBullet();
                    }
                }
                #endregion

                #region Jump commands
                if (!jumping)
                {
                    if (keyboardState.IsKeyDown(Keys.LeftControl) || keyboardState.IsKeyDown(Keys.RightControl))
                    {
                        drawJump = true;
                    }

                    if (keyboardState.IsKeyUp(Keys.LeftControl) && keyboardState.IsKeyUp(Keys.RightControl))
                    {
                        drawJump = false;
                    }
                }
                else
                {
                    currentJumpCount++;
                    if (currentJumpCount > jumpCount)
                    {
                        theWorld.player.VX = 0;
                        theWorld.player.VY = 0;
                        jumping = false;
                        theWorld.player.checkForCollision = true;
                        jumpCount = 0;
                        currentJumpCount = 0;
                    }
                }
                #endregion
                // TODO: Add your update logic here
                theWorld.Update(gameTime);

                //Camera code
                cameraPos = -theWorld.objects["player"].Location;
                cameraTransform = Matrix.CreateTranslation(cameraPos.X, cameraPos.Y, 0.0f) * Matrix.CreateTranslation(viewportSize.Width * 0.5f, viewportSize.Height * 0.5f, 0);

                

               
            }
            base.Update(gameTime);
            if (timeCheck > 20)//prevents int from getting too big
                timeCheck = 20;
        }


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            if (!theWorld.levelLoading)
            {
                Line l = (Line)theWorld.objects["jumpLine"];
                //l.lineColor = Color.White;
                GraphicsDevice.Clear(Color.SkyBlue);


                spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default,
                         RasterizerState.CullCounterClockwise, null, cameraTransform);

                if (!ovManager.hold)
                {
                    //Draw inventory
                    if (drawInventory)
                        DrawInventory();

                    if (drawJump)
                        l.showingUp = true;
                    else
                        l.showingUp = false;

                    //Draw world
                    theWorld.Draw(spriteBatch);
                }
                //Draw overlay(s)
                ovManager.Draw(spriteBatch);
                spriteBatch.End();

                base.Draw(gameTime);
            }
            else
                GraphicsDevice.Clear(Color.Black);
        }

        private void DrawInventory()
        {
            spriteBatch.Draw(Storage.getTexture("redpixel"), inventoryBox, null,Color.White,0,new Vector2(0,0),SpriteEffects.None, 0.2f);
            Player tempPlayer = (Player)theWorld.objects["player"];
            Vector2 vec = new Vector2((inventoryBox.X + 25), (inventoryBox.Y + 10));
            string hover = "";
            foreach (Item i in tempPlayer.Inventory)
            {
                if (i == null)
                    break;
                spriteBatch.DrawString(arial, i.Name, vec, i.InventoryColor, 0, new Vector2(0,0),1,SpriteEffects.None,0.1f);
                vec.Y += 23;
                if (i is Weapon)
                {
                    Weapon w = (Weapon)i;
                    hover = w.Name + '\n' + w.EnergyCurr + " / " + w.EnergyMax + '\n';
                }
            }
            spriteBatch.Draw(Storage.getTexture("tempPointer"), pointerLoc, Color.White);
        }

        public Vector2 GetCameraPos()
        {
            return new Vector2(cameraTransform.M41, cameraTransform.M42);
        }
    }
}
